﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using OpenTK;

namespace Chimp.Core
{
    public class ChimpFXNode
    {
        public static Dictionary<string, ChimpFXNode> NodeMap = new Dictionary<string, ChimpFXNode>();
        public static Dictionary<string, ChimpEffectPar> ParMap = new Dictionary<string, ChimpEffectPar>();
        public List<ChimpEffectPar> In = new List<ChimpEffectPar>();
        public List<ChimpEffectPar> Out = new List<ChimpEffectPar>();

        public ChimpFXNode()
        {
            UIPos = Vector2.Zero;
            UIWidth = UIHeight = 0;
            ID = "";
            NodeType = EffectNodeType.Constant;
            PropNodeName = "";
            PropComment = "";
        }

        public ChimpFXNode(string id, EffectNodeType type)
        {
            ID = id;
            NodeType = type;
            PropComment = "";
            PropNodeName = id;
        }

        public Vector2 UIPos { get; set; }
        public float UIWidth { get; set; }
        public float UIHeight { get; set; }
        public string ID { get; set; }
        public EffectNodeType NodeType { get; set; }

        public string PropNodeName { get; set; }
        public string PropComment { get; set; }

        public void WriteParameters(BinaryWriter w)
        {
            foreach (ChimpEffectPar n in In)
            {
                WriteParameter(w, n);
            }
            foreach (ChimpEffectPar n in Out)
            {
                WriteParameter(w, n);
            }
        }

        private void WriteParameter(BinaryWriter w, ChimpEffectPar p)
        {
            w.Write(p.ID);
            w.Write(PropNodeName + "_" + p.ID);
            w.Write((int) p.Type);
            if (p.To != null)
            {
                w.Write(true);
                w.Write(p.To.Owner.PropNodeName + "_" + p.To.ID);
            }
            else
            {
                w.Write(false);
            }
            w.Write(p.Owner.PropNodeName);
        }

        public static ChimpEffectPar ReadParameter(BinaryReader r)
        {
            var p = new ChimpEffectPar();
            p.ID = r.ReadString();
            p.ThisName = r.ReadString();
            p.Type = (EffectParameterType) r.ReadInt32();
            if (r.ReadBoolean())
            {
                p.ToName = r.ReadString();
            }
            else
            {
                p.ToName = "None";
            }
            p.OwnerName = r.ReadString();
            return p;
        }

        public void WriteNode(BinaryWriter w)
        {
            w.Write(GetType().Name);
            w.Write(UIPos.X);
            w.Write(UIPos.Y);
            w.Write(UIWidth);
            w.Write(UIHeight);
            w.Write(ID);
            w.Write((int) NodeType);
            //w.Write(PropNodeName);
            //w.Write(PropComment);
            WriteProperties(w);
            w.Write(In.Count);
            foreach (ChimpEffectPar ep in In)
            {
                w.Write(PropNodeName + "_" + ep.ID);
            }
            w.Write(Out.Count);
            foreach (ChimpEffectPar ep in Out)
            {
                w.Write(PropNodeName + "_" + ep.ID);
            }
        }

        public void ReadProperties(BinaryReader w)
        {
            Type t = GetType();
            foreach (PropertyInfo p in t.GetProperties())
            {
                if (p.Name.Length < 5) continue;
                if (p.Name.Substring(0, 4) == "Prop")
                {
                    Type tc = p.PropertyType;

                    if (tc == typeof (int))
                    {
                        p.SetValue(this, w.ReadInt32(), null);
                        //  w.Write((byte)0);
                        //w.Write(int.Parse(p.GetValue(this, null).ToString()));
                    }
                    if (tc == typeof (float))
                    {
                        p.SetValue(this, w.ReadSingle(), null);
                        //    w.Write((byte)1);
                        //    w.Write(float.Parse(p.GetValue(this, null).ToString()));
                    }
                    if (tc == typeof (string))
                    {
                        p.SetValue(this, w.ReadString(), null);
                        //w.Write(p.GetValue(this, null).ToString());
                    }
                    if (tc == typeof (bool))
                    {
                        p.SetValue(this, w.ReadBoolean(), null);
                        //w.Write((bool)p.GetValue(this, null));
                    }
                }
            }
        }

        public void WriteProperties(BinaryWriter w)
        {
            Type t = GetType();
            foreach (PropertyInfo p in t.GetProperties())
            {
                if (p.Name.Length < 5) continue;
                if (p.Name.Substring(0, 4) == "Prop")
                {
                    Type tc = p.PropertyType;

                    if (tc == typeof (int))
                    {
                        //  w.Write((byte)0);
                        w.Write(int.Parse(p.GetValue(this, null).ToString()));
                    }
                    if (tc == typeof (float))
                    {
                        //    w.Write((byte)1);
                        w.Write(float.Parse(p.GetValue(this, null).ToString()));
                    }
                    if (tc == typeof (string))
                    {
                        w.Write(p.GetValue(this, null).ToString());
                    }
                    if (tc == typeof (bool))
                    {
                        w.Write((bool) p.GetValue(this, null));
                    }
                }
            }
        }

        public static ChimpFXNode ReadNode(BinaryReader w)
        {
            string nt = w.ReadString();
            var rn = Activator.CreateInstance(Type.GetType("Xeno.Core." + nt)) as ChimpFXNode;
            rn.In.Clear();
            rn.Out.Clear();
            rn.ReadNodeAux(w);

            return rn;
        }

        public void ReadNodeAux(BinaryReader w)
        {
            UIPos = new Vector2(w.ReadSingle(), w.ReadSingle());
            UIWidth = w.ReadSingle();
            UIHeight = w.ReadSingle();
            ID = w.ReadString();
            NodeType = (EffectNodeType) w.ReadInt32();
            ReadProperties(w);
            int ic = w.ReadInt32();
            for (int i = 0; i < ic; i++)
            {
                string s = w.ReadString();
                In.Add(ParMap[s]);
            }
            int oc = w.ReadInt32();
            for (int i = 0; i < oc; i++)
            {
                string s = w.ReadString();
                Out.Add(ParMap[s]);
            }
        }

        public virtual ChimpFXNode CreateNew()
        {
            return new ChimpFXNode(ID, NodeType);
        }

        public string InTo(int i)
        {
            return In[i].To.Owner.PropNodeName + "_" + In[i].To.ID;
        }

        public ChimpEffectPar GetIn(string id)
        {
            return _FindPar(id, In);
        }

        public ChimpEffectPar _FindPar(string id, List<ChimpEffectPar> pars)
        {
            foreach (ChimpEffectPar p in pars)
            {
                if (p.ID == id)
                {
                    return p;
                }
            }
            return null;
        }

        public void AddIn(EffectParameterType type, string id, string info)
        {
            var ep = new ChimpEffectPar(id, type);
            In.Add(ep);
            ep.Owner = this;
        }

        public void AddOut(EffectParameterType type, string id, string info)
        {
            var ep = new ChimpEffectPar(id, type);
            Out.Add(ep);
            ep.Owner = this;
        }

        public virtual void ProduceSegment(List<ChimpEffectPar> pars)
        {
            return;
        }
    }
}